﻿using System;
using System.Threading;
using agsXMPP;
using NUnit.Framework;
using Rhino.Mocks;
using XcoAppSpaces.Transport.Jabber;
using XcoAppSpaces.Contracts.Transport;
using XcoAppSpaces.Contracts.Logging;
using XcoAppSpaces.Contracts.Serialization;

namespace test.XcoAppSpaces.Transport.Jabber
{
    [TestFixture]
    public class testXcoJabberTransportService
    {
        //private const string JID1 = "plum@tfsvs08/res001";
        //private const string PWD1 = "plumplum";

        //private const string JID1RES002 = "plum@tfsvs08/res002";

        //private const string JID2 = "plisch@tfsvs08/res002";
        //private const string PWD2 = "plisch";

        private const string JID1 = "xco001@jabber.org/res001";
        private const string PWD1 = "xco001";

        private const string JID1RES002 = "xco001@jabber.org/res002";

        private const string JID2 = "xco002@jabber.org/res002";
        private const string PWD2 = "xco002";


        private const string JID1WithHostname = "xco001@ag-software.de";
        private const string PWD1WithHostname = "xco001";

        private const string JID2WithHostname = "xco002@ag-software.de";
        private const string PWD2WithHostname = "xco002";
        private const string HOSTNAME = "xmpp.ag-software.de";
        private MessageSerializer serializer = new MessageSerializer();
		[SetUp]
		public void SetUp()
		{
			XcoLoggerFactory.CreateInstance = (t => new ConsoleLogger());
		}


     /*   [Test]
        public void ConnectToServer()
        {
            using(XcoJabberTransportService js = new XcoJabberTransportService(JID1, PWD1))
            {
                js.Start(null, null);
                Assert.IsTrue(js.Running);
            }
        }*/

     /*   [Test]
        public void ReleaseConnectionOnStop()
        {
            XcoJabberTransportService js = new XcoJabberTransportService(JID1, PWD1);
            try
            {
                js.Start(null, null);
                Assert.IsTrue(js.Running);
                js.Stop();
                Assert.IsFalse(js.Running);
            }
            finally
            {
                js.Stop();                
            }

            using(js = new XcoJabberTransportService(JID1, PWD1))
            {
                js.Start(null, null);
                Assert.IsTrue(js.Running);
            }
            Assert.IsFalse(js.Running);
        }*/

        
       /* [Test]
        public void ReleaseConnectionOnDispose()
        {
            XcoJabberTransportService js;
            using (js = new XcoJabberTransportService(JID1, PWD1))
            {
                js.Start(null, null);
                Assert.IsTrue(js.Running);
            }
            Assert.IsFalse(js.Running);
        }*/

        [Test]
        public void CheckConnectionProperties()
        {
            using (XcoJabberTransportService js = new XcoJabberTransportService(JID1, PWD1))
            {
                js.Start();

                Jid jid = new Jid(JID1);
                Assert.AreEqual(jid.ToString(), js.LocalAddress);
            }
        }

		//[Test]
		//public void CheckLogging()
		//{
		//    IXcoLogger logger = MockRepository.GenerateMock<IXcoLogger>();
		//    IXcoLoggerFactory loggerfactory = MockRepository.GenerateStub<IXcoLoggerFactory>();
		//    loggerfactory.Expect(x => loggerfactory.CreateInstance("x", typeof (IXcoLoggerFactory))).IgnoreArguments().Return(logger);


		//    using (XcoJabberTransportService js = new XcoJabberTransportService(JID1, PWD1))
		//    {
		//        js.SetLogger(loggerfactory);
		//        js.Start(null, null);
		//    }

		//    logger.AssertWasCalled(x => x.Info("Logging started"));
		//    logger.AssertWasCalled(x => x.Info("Starting communication service"));
		//}


        //[Test]
        //public void SendMessageToIMClient()
        //{
        //    using (XcoJabberTransportService js = new XcoJabberTransportService(JID1, PWD1))
        //    {
        //        IXcoLoggerFactory loggerfactory = MockRepository.GenerateStub<IXcoLoggerFactory>();
        //        loggerfactory.Expect(x => loggerfactory.CreateInstance("x", typeof(IXcoLoggerFactory))).IgnoreArguments().Return(new ConsoleLogger());
        //        js.SetLogger(loggerfactory);

        //        js.Start(null, 0, null, new MessageSerializer());
        //        Message msg = new Message("plum@tfsvs08/visualstudio", "XYZ");
        //        js.SendMessage(msg);
        //    }
        //}


        [Test]
        public void SendAndReceiveMessage()
        {
            SendAndReceiveMessage(JID1, PWD1, JID2, PWD2, "");
        }

        [Test]
        public void SendAndReceiveMessageSameJidDifferentResources()
        {
            SendAndReceiveMessage(JID1, PWD1, JID1RES002, PWD1, "");
        }

        [Test]
        public void SendAndReceiveMessageWithHostname()
        {
            SendAndReceiveMessage(JID1WithHostname, PWD1WithHostname, JID2WithHostname, PWD2WithHostname, "");
            SendAndReceiveMessage(JID1WithHostname, PWD1WithHostname, JID2WithHostname, PWD2WithHostname, HOSTNAME);
        }


        private void SendAndReceiveMessage(string clientJid, string clientPwd, string serverJid, string serverPwd, string hostname)
        {
            using (XcoJabberTransportService js1 = new XcoJabberTransportService(clientJid, clientPwd, hostname))
            using (XcoJabberTransportService js2 = new XcoJabberTransportService(serverJid, serverPwd, hostname))
            {
				//IXcoLoggerFactory loggerfactory1 = MockRepository.GenerateStub<IXcoLoggerFactory>();
				//loggerfactory1.Expect(x => loggerfactory1.CreateInstance("js1", typeof(IXcoLoggerFactory))).IgnoreArguments().Return(new ConsoleLogger { ID = clientJid });
				//js1.SetLogger(loggerfactory1);

				//IXcoLoggerFactory loggerfactory2 = MockRepository.GenerateStub<IXcoLoggerFactory>();
				//loggerfactory2.Expect(x => loggerfactory2.CreateInstance("js2", typeof(IXcoLoggerFactory))).IgnoreArguments().Return(new ConsoleLogger { ID = serverJid });
				//js2.SetLogger(loggerfactory2);
				
				js1.Start();

                ReceivedTmp tmp = new ReceivedTmp();
                tmp.are = new AutoResetEvent(false);
                tmp.msgReceived = null;
				js2.OnMessageReceived += tmp.MessageReceived;
				
                js2.Start();

                byte[] data = serializer.Serialize(new Message("abcäöü"));
				js1.Send(new XcoMessage { Content = data }, serverJid);

                Assert.IsTrue(tmp.are.WaitOne(10000));
                Assert.IsNotNull(tmp.msgReceived);
                //Assert.IsTrue(tmp.msgReceived.RemoteAddress.StartsWith(clientJid));
                Assert.AreEqual("abcäöü", tmp.msgReceived.Payload);
            }
        }
    }


    #region Mocks
    class Message 
    {
        public string Payload;

        public Message( string payload)
        {
            this.Payload = payload;
        }
    }


    class MessageSerializer : IXcoSerializer
    {

        #region IXcoSerializer Members

        public object Deserialize(System.IO.Stream stream)
        {
            throw new System.NotImplementedException();
        }

        public object Deserialize(byte[] element)
        {
            return new Message( new string(System.Text.Encoding.UTF8.GetChars(element)));
        }

        public byte[] Serialize(object element)
        {
            Message msg = element as Message;
            if (msg == null) throw new ArgumentException("Can only serialize Message objects!");

            return System.Text.Encoding.UTF8.GetBytes(msg.Payload);
        }

        public void SetSurrogateSelector(System.Runtime.Serialization.ISurrogateSelector surrogateSelector)
        {
            throw new System.NotImplementedException();
        }

		public bool CanTypeBeSerialized(Type type, out string errorInfo)
		{
			errorInfo = null;
			return true;
		}

        #endregion

		#region IXcoService Members

		public void Initialize(global::XcoAppSpaces.Contracts.Service.IXcoServiceRegistry serviceRegistry)
		{
		}

		#endregion
	}
    #endregion
}
